Sensor Fusion for Kinetis MCUs (ISSDK/KSDK version)
main_freertos_agm02_power_cycling.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016, NXP Semiconductor, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * o Redistributions of source code must retain the above copyright notice, this list
9  * of conditions and the following disclaimer.
10  *
11  * o Redistributions in binary form must reproduce the above copyright notice, this
12  * list of conditions and the following disclaimer in the documentation and/or
13  * other materials provided with the distribution.
14  *
15  * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from this
17  * software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 /*! \file main_freertos_agm02_power_cycling.c
31  \brief FreeRTOS (two task) implementation of sensor fusion on FRDM-K64F/FRDM-FXS-AGM02 with smart power-cycling support.
32 
33  This file shows one recommended way to incorporate sensor fusion capabilities
34  into a FreeRTOS project AND adds intelligent power down of sensors when
35  the DUT is stationary.
36 */
37 
38 // KSDK and ISSDK Headers
39 #include "fsl_debug_console.h" // KSDK header file for the debug interface
40 #include "FSL_SMC.H" // KDSK header file for the System Mode Controller Driver
41 #include "board.h" // KSDK header file to define board configuration
42 #include "pin_mux.h" // KSDK header file for pin mux initialization functions
43 #include "clock_config.h" // KSDK header file for clock configuration
44 #include "fsl_port.h" // KSDK header file for Port I/O control
45 #include "fsl_i2c.h" // KSDK header file for I2C interfaces
46 #include "Driver_I2C.h"
47 #include "Driver_I2C_SDK2.h"
48 
49 // Sensor Fusion Headers
50 #include "sensor_fusion.h" // top level magCal and sensor fusion interfaces
51 #include "control.h" // Command/Streaming interface - application specific
52 #include "status.h" // Status indicator interface - application specific
53 #include "drivers.h" // NXP sensor drivers OR customer-supplied drivers
54 #include "fusion.h" // Need lower level function for power management
55 
56 /* FreeRTOS kernel includes. */
57 #include "FreeRTOS.h"
58 #include "task.h"
59 #include "queue.h"
60 #include "timers.h"
61 #include "event_groups.h"
62 
63 // Global data structures
64 SensorFusionGlobals sfg; ///< This is the primary sensor fusion data structure
65 ControlSubsystem controlSubsystem; ///< used for serial communications
66 StatusSubsystem statusSubsystem; ///< provides visual (usually LED) status indicator
67 PhysicalSensor sensors[3]; ///< This implementation uses three physical sensors
68 EventGroupHandle_t event_group = NULL;
70 {
71  // MCU low power modes are not debugged at this point in time
72  //volatile smc_power_state_t state;
73  //SMC_SetPowerModeStop(SMC, kSMC_PartialStop );
74  //state = SMC_GetPowerModeState(SMC);
75  //asm("wfi");
76 }
78 {
79  sfg.queueStatus(&sfg, NORMAL); // assume NORMAL status for next pass through the loop
80 }
81 
82 static void read_task(void *pvParameters);
83 static void fusion_task(void *pvParameters);
84 bool motionCheck( float sample[3],
85  float baseline[3],
86  float tolerance,
87  uint32_t winLength,
88  uint32_t *count); // defined in motionCheck.c
89 /// This is a FreeRTOS (dual task) implementation of the NXP sensor fusion demo build.
90 int main(void)
91 {
92  ARM_DRIVER_I2C* I2Cdrv = &I2C_S_DRIVER_BLOCKING; // defined in the <shield>.h file
93  BOARD_InitPins(); // defined in pin_mux.c, initializes pkg pins
94  BOARD_BootClockRUN(); // defined in clock_config.c, initializes clocks
95  BOARD_InitDebugConsole(); // defined in board.c, initializes the OpenSDA port
96 
97  I2Cdrv->Initialize(NULL); // Initialize the KSDK driver for the I2C port
98  I2Cdrv->Control(ARM_I2C_BUS_SPEED, ARM_I2C_BUS_SPEED_FAST); // Configure the I2C bus speed
99 
100  initializeControlPort(&controlSubsystem); // configure pins and ports for the control sub-system
101  initializeStatusSubsystem(&statusSubsystem); // configure pins and ports for the status sub-system
102  initSensorFusionGlobals(&sfg, &statusSubsystem, &controlSubsystem); // Initialize sensor fusion structures
103  // "install" the sensors we will be using
104  sfg.installSensor(&sfg, &sensors[0], FXLS8952C_I2C_ADDR, 1, (void*) I2Cdrv, FXLS8952_Init, FXLS8952_Read);
105  sfg.installSensor(&sfg, &sensors[1], FXAS21002_I2C_ADDR, 1, (void*) I2Cdrv, FXAS21002_Init, FXAS21002_Read);
106  sfg.installSensor(&sfg, &sensors[2], MAG3110_I2C_ADDR, 1, (void*) I2Cdrv, MAG3110_Init, MAG3110_Read);
107  sfg.initializeFusionEngine(&sfg); // This will initialize sensors and magnetic calibration
108 
109  event_group = xEventGroupCreate();
110  xTaskCreate(read_task, "READ", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 2, NULL);
111  xTaskCreate(fusion_task, "FUSION", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);
112 
113  sfg.setStatus(&sfg, NORMAL); // If we got this far, let's set status state to NORMAL
114  vTaskStartScheduler(); // Start the RTOS scheduler
115  sfg.setStatus(&sfg, HARD_FAULT); // If we got this far, FreeRTOS does not have enough memory allocated
116  for (;;) ;
117 }
118 
119 static void read_task(void *pvParameters)
120 {
121  uint16_t i=0; // general counter variable
122  portTickType lastWakeTime;
123  const portTickType frequency = 1; // tick counter runs at the read rate
124  lastWakeTime = xTaskGetTickCount();
125  while (1)
126  {
127  for (i=1; i<=OVERSAMPLE_RATE; i++) {
128  vTaskDelayUntil(&lastWakeTime, frequency);
129  sfg.readSensors(&sfg, i); // Reads sensors, applies HAL and does averaging (if applicable)
130  }
131  xEventGroupSetBits(event_group, B0);
132  }
133 }
134 
135 static void fusion_task(void *pvParameters)
136 {
137  uint16_t i=0; // general counter variable
138  float motion_baseline[3] = {0.0, 0.0, 0.0};
139  bool stationary;
140  static bool lastStationary;
141  uint32_t stationaryCount = 0;
142  while (1)
143  {
144  xEventGroupWaitBits(event_group, /* The event group handle. */
145  B0, /* The bit pattern the event group is waiting for. */
146  pdTRUE, /* BIT_0 and BIT_4 will be cleared automatically. */
147  pdFALSE, /* Don't wait for both bits, either bit unblock task. */
148  portMAX_DELAY); /* Block indefinitely to wait for the condition to be met. */
149 
150  // sfg.runFusion(&sfg); // Run the actual fusion algorithms
151  // Rather than call runFusion directly, this example invokes the lower level
152  // calls here. This allows us to check to see if the board is stationary,
153  // and if so, transition to a lower power state.
154  sfg.conditionSensorReadings(&sfg); // magCal is run as part of this
155  stationary = motionCheck(
156  sfg.Accel.fGc, // calibrated accelerometer reading
157  motion_baseline, // baseline to check new values against
158  0.01, // changes less than this are ignored
159  120, // three seconds at 40Hz rate
160  &stationaryCount);
161  if (stationary) {
162  if (!lastStationary) { // suspend some operations
163  FXAS21002_Idle(&(sensors[1]), &sfg);
164  MAG3110_Idle(&(sensors[2]), &sfg);
165  }
166  sfg.clearFIFOs(&sfg);
167  } else {
168  if (lastStationary) { // restart operations
169  FXAS21002_Init(&(sensors[1]), &sfg);
170  MAG3110_Init(&(sensors[2]), &sfg);
171  }
172  // fuse the sensor data
173  sfg.runFusion(&sfg);
174  }
175 
176  sfg.applyPerturbation(&sfg); // apply debug perturbation (testing only)
177 
178  sfg.loopcounter++; // The loop counter is used to "serialize" mag cal operations
179  i=i+1;
180  if (i>=4) { // Some status codes include a "blink" feature. This loop
181  i=0; // should cycle at least four times for that to operate correctly.
182  sfg.updateStatus(&sfg); // This is where pending status updates are made visible
183  }
184  if (stationary) {
185  sfg.queueStatus(&sfg, LOWPOWER); // assume LOWPOWER status for next pass through the loop
186  } else {
187  sfg.queueStatus(&sfg, NORMAL); // assume NORMAL status for next pass through the loop
188  }
189  sfg.pControlSubsystem->stream(&sfg, sUARTOutputBuffer); // Send stream data to the Sensor Fusion Toolbox
190  lastStationary = stationary;
191  }
192 }
193 
194 /// \endcode
void initSensorFusionGlobals(SensorFusionGlobals *sfg, StatusSubsystem *pStatusSubsystem, ControlSubsystem *pControlSubsystem)
utility function to insert default values in the top level structure
Definition: sensor_fusion.c:68
#define OVERSAMPLE_RATE
int8_t FXLS8952_Read(PhysicalSensor *sensor, SensorFusionGlobals *sfg)
void vApplicationIdleHook(void)
int32_t loopcounter
counter incrementing each iteration of sensor fusion (typically 25Hz)
clearFIFOs_t * clearFIFOs
clear sensor FIFOs
conditionSensorReadings_t * conditionSensorReadings
preprocessing step for sensor fusion
Lower level sensor fusion interface.
int main(void)
This is a FreeRTOS (dual task) implementation of the NXP sensor fusion demo build.
bool motionCheck(float sample[3], float baseline[3], float tolerance, uint32_t winLength, uint32_t *count)
The motionCheck() function is not a sensor fusion function. It is a function that simply monitors an ...
Definition: motionCheck.c:44
void initializeStatusSubsystem(StatusSubsystem *pStatus)
initializeStatusSubsystem() should be called once at startup to initialize the data structure and to ...
Definition: status.c:185
The top level fusion structure.
streamData_t * stream
function to create packets for serial stream
Definition: control.h:73
EventGroupHandle_t event_group
installSensor_t * installSensor
function for installing a new sensor into t
SensorFusionGlobals sfg
This is the primary sensor fusion data structure.
StatusSubsystem() provides an object-like interface for communicating status to the user...
Definition: status.h:44
void vApplicationTickHook(void)
readSensors_t * readSensors
read all physical sensors
struct ControlSubsystem * pControlSubsystem
initializeFusionEngine_t * initializeFusionEngine
set sensor fusion structures to initial values
#define B0
Definition: sensor_fusion.h:88
PhysicalSensor sensors[3]
This implementation uses three physical sensors.
updateStatus_t * updateStatus
status=next status
int8_t FXAS21002_Read(PhysicalSensor *sensor, SensorFusionGlobals *sfg)
The sensor_fusion.h file implements the top level programming interface.
int8_t MAG3110_Read(PhysicalSensor *sensor, SensorFusionGlobals *sfg)
Running in reduced power mode.
Provides function prototypes for driver level interfaces.
he ControlSubsystem encapsulates command and data streaming functions.
Definition: control.h:64
uint8_t sUARTOutputBuffer[256]
main output buffer defined in control.c
Definition: control.c:59
static void fusion_task(void *pvParameters)
ControlSubsystem controlSubsystem
used for serial communications
int8_t initializeControlPort(ControlSubsystem *pComm)
Initialize the control subsystem and all related hardware.
Definition: control.c:182
runFusion_t * runFusion
run the fusion routines
int8_t FXLS8952_Init(PhysicalSensor *sensor, SensorFusionGlobals *sfg)
ARM_DRIVER_I2C * I2Cdrv
KSDK handle for the I2C port defined in Driver_I2C_KSDK2.c.
int8_t FXAS21002_Idle(PhysicalSensor *sensor, SensorFusionGlobals *sfg)
Non-recoverable FAULT = something went very wrong.
Application-specific status subsystem.
An instance of PhysicalSensor structure type should be allocated for each physical sensors (combo dev...
int8_t MAG3110_Init(PhysicalSensor *sensor, SensorFusionGlobals *sfg)
setStatus_t * queueStatus
queue status change for next regular interval
Defines control sub-system.
int8_t MAG3110_Idle(PhysicalSensor *sensor, SensorFusionGlobals *sfg)
setStatus_t * setStatus
change status indicator immediately
static void read_task(void *pvParameters)
applyPerturbation_t * applyPerturbation
apply step function for testing purposes
int8_t FXAS21002_Init(PhysicalSensor *sensor, SensorFusionGlobals *sfg)
Operation is Nominal.
StatusSubsystem statusSubsystem
provides visual (usually LED) status indicator